/**
 * 处理器
 * @author zj
 * @date 2024/08/22
 */

import {Configure} from './configure.ts';
import {BindKeyInfo, ChildProps, HandleData, ItemAttrs, ParentData, RelationWrapperData} from './types.ts';
import {getFirstLowerStartPrefix, getUuid, isArray, isObject} from './utils.ts';
import {createChildWrapper, createRelationWrapper, handleChildProp, handleChildProps, setBindKeys} from './common.ts';

/**
 * 类型处理器
 */
export interface TypeHandler {

  /**
   * 类型名称
   */
  getType(): string;

  /**
   * 获取子类型，只有下级类型是唯一的才返回，例如 grid的下级只能是 grid-item
   */
  getChildType(): string | undefined;

  /**
   * 处理函数
   */
  doHandler(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): HandleData | undefined;

}

/**
 * 前置处理器
 */
export interface BeforeHandler {

  doBefore(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void;

}

/**
 * 后置处理器
 */
export interface AfterHandler {

  doAfter(childProps: ChildProps, itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): void;

}

/**
 * 属性处理器
 */
export interface PropHandler {

  doHandle(key: string, value: string, childProps: ChildProps, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean;

}

/**
 * 相关处理器
 */
export interface RelationHandler extends BeforeHandler {

  getType(): string;

  getChildType(): string | undefined;

  isMatch(itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean;

  isHandleProp(): boolean;

  getMatchProps(): string[];

  getSlotName(): string;

  getChildrenRelations(): RelationHandler[] | undefined;

  doHandle(key: string, value: string, childProps: ChildProps, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean;

}

/**
 * 属性处理器管理器
 */
export interface PropHandlerManger extends PropHandler, BeforeHandler {

}

/**
 * 前置处理器管理器
 */
export interface BeforeHandlerManger extends BeforeHandler {

}

/**
 * 后置处理器管理器
 */
export interface AfterHandlerManger extends AfterHandler {

}

/**
 * 相关处理器管理器
 */
export interface RelationHandlerManger {

  getMatchRelations(itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): RelationHandler[];

}

/**
 * 处理器管理器
 */
export interface HandlerManger {

  /**
   * 处理函数
   * @param itemAttrs
   * @param bindKeys
   * @param parentData
   * @param configure
   */
  doHandle(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): HandleData | undefined;

  /**
   * 获取处理器
   */
  getHandler(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): TypeHandler;

}

/**
 * 默认属性处理器
 */
export class DefaultPropHandler implements PropHandler {
  protected _props?: Record<string, string>;
  protected _prefix?: string;

  constructor(props: Record<string, string> | undefined, prefix?: string) {
    this._props = props;
    this._prefix = prefix;
  }

  doHandle(key: string, value: string, childProps: ChildProps, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    if (this.fixedPropHandle(key, value, childProps, itemAttrs, parentData, configure)) {
      return true;
    }
    // noinspection RedundantIfStatementJS
    if (this.prefixPropHandle(key, value, childProps, itemAttrs, parentData, configure)) {
      return true;
    }
    return false;
  }

  fixedPropHandle(key: string, value: string, childProps: ChildProps, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    const realPropName = this.getRealPropName(key);
    if (realPropName) {
      childProps.props[realPropName] = value;
      return true;
    }
  }

  prefixPropHandle(key: string, value: string, childProps: ChildProps, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    const prefix = this._prefix;
    if (prefix) {
      const realPropName = getFirstLowerStartPrefix(key, prefix);
      if (realPropName) {
        childProps.props[realPropName] = value;
        return true;
      }
    }
    return false;
  }

  getRealPropName(key: string) {
    const props = this._props;
    if (props) {
      const realPropName = props[key];
      if (realPropName) {
        return realPropName;
      }
    }
  }

}

/**
 * 默认属性处理器管理器
 */
export class DefaultPropHandlerManger implements PropHandlerManger {
  protected _inherits?: Record<string, string>;
  protected _bindsName?: string;
  protected _disabledKey?: string;
  protected _loadingKey?: string;
  protected _propHandlers?: PropHandler[];

  constructor(propHandlers?: PropHandler[]) {
    this._propHandlers = propHandlers;
  }

  setPropHandlers(propHandlers?: PropHandler[]) {
    this._propHandlers = propHandlers;
  }

  addPropHandler(propHandler?: PropHandler) {
    if (propHandler) {
      if (this._propHandlers) {
        this._propHandlers.push(propHandler);
      } else {
        this._propHandlers = [propHandler];
      }
    }
  }

  setInherits(inherits: Record<string, string> | undefined) {
    this._inherits = inherits;
  }

  setBindsName(bindsName?: string) {
    this._bindsName = bindsName;
  }

  setDisabledKey(disabledKey?: string) {
    this._disabledKey = disabledKey;
  }

  setLoadingKey(loadingKey?: string) {
    this._loadingKey = loadingKey;
  }

  doHandle(key: string, value: string, childProps: ChildProps, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    const propHandlers = this._propHandlers;
    if (propHandlers && propHandlers.length > 0) {
      for (let i = 0; i < propHandlers.length; i++) {
        const propHandler = propHandlers[i];
        if (propHandler.doHandle(key, value, childProps, itemAttrs, parentData, configure)) {
          return true;
        }
      }
    }
    return false;
  }

  doBefore(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void {
    this.handleBindsName(childProps, itemAttrs, ignoreAttrNames, parentData, configure);
    this.handleInherits(childProps, itemAttrs, ignoreAttrNames, parentData, configure);
    this.handleDefault(childProps, itemAttrs, ignoreAttrNames, parentData, configure);
  }

  handleBindsName(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void {
    const key = this._bindsName;
    if (key) {
      const value = itemAttrs[key];
      if (value) {
        if (isObject(value) && !isArray(value)) {
          Object.assign(childProps.props, value);
          ignoreAttrNames[key] = true;
        }
      }
    }
  }

  handleInherits(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void {
    const inherits = this._inherits;
    if (inherits) {
      for (const key of Object.keys(inherits)) {
        if (inherits.hasOwnProperty(key)) {
          const value = parentData[key];
          if (value) {
            const childKey = inherits[key];
            if (childKey) {
              childProps.props[childKey] = value;
            }
          }
        }
      }
    }
  }

  handleDefault(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void {
    // 设置禁用属性
    const disabledKey = this._disabledKey;
    if (disabledKey) {
      childProps.disabledKey = itemAttrs[disabledKey] || configure.getDisabledKey();
      ignoreAttrNames[disabledKey] = true;
    }
    // 设置加载属性
    const loadingKey = this._loadingKey;
    if (loadingKey) {
      childProps.loadingKey = itemAttrs[loadingKey];
      ignoreAttrNames[loadingKey] = true;
    }
  }

}

/**
 * 默认前置处理器管理器
 */
export class DefaultBeforeHandlerManger implements BeforeHandlerManger {
  protected _beforeHandlers?: BeforeHandler[];

  constructor(beforeHandlers?: BeforeHandler[]) {
    this._beforeHandlers = beforeHandlers;
  }

  setBeforeHandlers(beforeHandlers?: BeforeHandler[]) {
    this._beforeHandlers = beforeHandlers;
  }

  addBeforeHandler(beforeHandler?: BeforeHandler) {
    if (beforeHandler) {
      if (this._beforeHandlers) {
        this._beforeHandlers.push(beforeHandler);
      } else {
        this._beforeHandlers = [beforeHandler];
      }
    }
  }

  doBefore(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void {
    const beforeHandlers = this._beforeHandlers;
    if (beforeHandlers && beforeHandlers.length > 0) {
      for (let i = 0; i < beforeHandlers.length; i++) {
        const beforeHandler = beforeHandlers[i];
        if (beforeHandler) {
          beforeHandler.doBefore(childProps, itemAttrs, ignoreAttrNames, parentData, configure);
        }
      }
    }
  }

}

/**
 * 通用后置处理器
 */
export class CommonAfterHandler implements AfterHandler {

  doAfter(childProps: ChildProps, itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure?: Configure): void {

  }

}

/**
 * 默认后置处理器管理器
 */
export class DefaultAfterHandlerManger implements AfterHandlerManger {
  protected _afterHandlers?: AfterHandler[];

  constructor(afterHandlers?: AfterHandler[]) {
    this._afterHandlers = afterHandlers;
  }

  setAfterHandlers(afterHandlers?: AfterHandler[]) {
    this._afterHandlers = afterHandlers;
  }

  addAfterHandler(afterHandler?: AfterHandler) {
    if (afterHandler) {
      if (this._afterHandlers) {
        this._afterHandlers.push(afterHandler);
      } else {
        this._afterHandlers = [afterHandler];
      }
    }
  }

  doAfter(childProps: ChildProps, itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): void {
    const afterHandlers = this._afterHandlers;
    if (afterHandlers && afterHandlers.length > 0) {
      for (let i = 0; i < afterHandlers.length; i++) {
        const afterHandler = afterHandlers[i];
        if (afterHandler) {
          afterHandler.doAfter(childProps, itemAttrs, bindKeys, parentData, configure);
        }
      }
    }
  }
}

/**
 * 基础相关处理器
 */
export class BaseRelationHandler implements RelationHandler, AfterHandler {
  protected readonly _type: string;
  protected _childType?: string;
  protected _slotName?: string;
  protected _handleProp: boolean;
  protected _beforeHandlerManger?: BeforeHandlerManger;
  protected _afterHandlerManger?: AfterHandlerManger;
  protected _propHandlerManger?: PropHandlerManger;
  protected _relationHandlers?: RelationHandler[];

  constructor(type: string) {
    this._type = type;
  }

  setBeforeHandlerManger(beforeHandlerManger?: BeforeHandlerManger) {
    this._beforeHandlerManger = beforeHandlerManger;
  }

  setAfterHandlerManger(afterHandlerManger?: AfterHandlerManger) {
    this._afterHandlerManger = afterHandlerManger;
  }

  setPropHandlerManger(propHandlerManger?: PropHandlerManger) {
    this._propHandlerManger = propHandlerManger;
  }

  setRelationHandlers(relationHandlers?: RelationHandler[]) {
    this._relationHandlers = relationHandlers;
  }

  getType(): string {
    return this._type;
  }

  getChildType(): string | undefined {
    return this._childType;
  }

  isHandleProp(): boolean {
    return this._handleProp;
  }

  isMatch(itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    return false;
  }

  doBefore(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void {
    this._propHandlerManger?.doBefore(childProps, itemAttrs, ignoreAttrNames, parentData, configure);

    if (this._beforeHandlerManger) {
      this._beforeHandlerManger.doBefore(childProps, itemAttrs, ignoreAttrNames, parentData, configure);
    }
  }

  doAfter(childProps: ChildProps, itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): void {
    if (this._afterHandlerManger) {
      this._afterHandlerManger.doAfter(childProps, itemAttrs, bindKeys, parentData, configure);
    }
  }

  getMatchProps(): string[] {
    return [];
  }

  getSlotName(): string {
    return this._slotName || 'default';
  }

  getChildrenRelations(): RelationHandler[] | undefined {
    return this._relationHandlers;
  }

  setChildType(childType?: string) {
    this._childType = childType;
  }

  setSlotName(slotName?: string) {
    this._slotName = slotName;
  }

  setHandleProp(handleProp?: boolean) {
    if (handleProp === undefined) {
      this._handleProp = true;
    } else {
      this._handleProp = handleProp;
    }
  }

  setChildrenRelations(childrenRelations?: RelationHandler[]) {
    this._relationHandlers = childrenRelations;
  }

  doHandle(key: string, value: string, childProps: ChildProps, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    if (this._propHandlerManger) {
      return this._propHandlerManger.doHandle(key, value, childProps, itemAttrs, parentData, configure);
    }
    return false;
  }

}

/**
 * 属性匹配相关处理器
 */
export class KeyValueRelationHandler extends BaseRelationHandler {
  protected _propName?: string;
  protected _propValue?: any;

  setPropName(propName?: string) {
    this._propName = propName;
  }

  setPropValue(propValue?: any) {
    this._propValue = propValue;
  }

  isMatch(itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    if (this._propName) {
      const propValue = itemAttrs[this._propName];
      if (propValue !== undefined) {
        return propValue === this._propValue;
      }
    }

    return false;
  }

  getMatchProps(): string[] {
    if (this._propName) {
      return [this._propName];
    }
    return [];
  }
}

/**
 * 任何都能匹配的相关处理器
 */
export class AnyRelationHandler extends BaseRelationHandler {

  constructor() {
    super('*');
  }

  isMatch(itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    return true;
  }

  getMatchProps(): string[] {
    return [];
  }
}

/**
 * 任何都能匹配的相关处理器
 */
export class ExtendRelationHandler extends BaseRelationHandler {
  protected _extendAttrs: any;

  setExtendAttrs(extendAttrs: any) {
    this._extendAttrs = extendAttrs;
  }
}

/**
 * 自身匹配相关处理器
 */
export class MyselfRelationHandler extends BaseRelationHandler {

  isMatch(itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    return true;
  }

  getMatchProps(): string[] {
    return [];
  }
}

/**
 * 默认相关处理器管理器
 */
export class DefaultRelationHandlerManger implements RelationHandlerManger {
  protected _myselfHandler?: RelationHandler;
  protected _relationHandlers?: RelationHandler[];

  constructor(relationHandlers?: RelationHandler[]) {
    this._relationHandlers = relationHandlers;
  }

  setMyselfHandler(myselfHandler?: RelationHandler) {
    this._myselfHandler = myselfHandler;
  }

  setRelationHandlers(relationHandlers?: RelationHandler[]) {
    this._relationHandlers = relationHandlers;
  }

  addRelationHandler(relationHandler?: RelationHandler) {
    if (relationHandler) {
      if (this._relationHandlers) {
        this._relationHandlers.push(relationHandler);
      } else {
        this._relationHandlers = [relationHandler];
      }
    }
  }

  getMatchRelations(itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): RelationHandler[] {
    if (this._myselfHandler) {
      const relationHandlers: RelationHandler[] = [];
      relationHandlers.push(this._myselfHandler);
      this.matchChildrenRelations(relationHandlers, this._relationHandlers, itemAttrs, parentData, configure);
      if (relationHandlers.length > 1) {
        return relationHandlers;
      }
    }
    return [];
  }

  matchChildrenRelations(relationHandlers: RelationHandler[], relations: RelationHandler[] | undefined, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): void {
    if (relations && relations.length > 0) {
      for (let i = 0; i < relations.length; i++) {
        const relation = relations[i];
        if (relation) {
          if (relation.isMatch(itemAttrs, parentData, configure)) {
            relationHandlers.push(relation);
            this.matchChildrenRelations(relationHandlers, relation.getChildrenRelations(), itemAttrs, parentData, configure);
            return;
          }
        }
      }
    }
  }

}

/**
 * 基础处理器
 */
export class BaseTypeHandler implements TypeHandler, BeforeHandler, AfterHandler {
  protected _name?: string;
  protected _type: string;
  protected _childType?: string;
  protected _ignoreAttrNames: string[] = [];
  protected _propHandlerManger?: PropHandlerManger;
  protected _beforeHandlerManger?: BeforeHandlerManger;
  protected _afterHandlerManger?: AfterHandlerManger;

  constructor(type: string) {
    this._type = type;
  }

  setName(name?: string) {
    this._name = name;
  }

  getName(): string | undefined {
    return this._name;
  }

  setIgnoreAttrNames(ignoreAttrNames?: string[]) {
    this._ignoreAttrNames = ignoreAttrNames || [];
  }

  setBeforeHandlerManger(beforeHandlerManger?: BeforeHandlerManger) {
    this._beforeHandlerManger = beforeHandlerManger;
  }

  setAfterHandlerManger(afterHandlerManger?: AfterHandlerManger) {
    this._afterHandlerManger = afterHandlerManger;
  }

  setPropHandlerManger(propHandlerManger?: PropHandlerManger) {
    this._propHandlerManger = propHandlerManger;
  }

  get ignoreAttrNames(): Record<string, boolean> {
    return this._ignoreAttrNames.reduce((result, key) => {
      if (key) {
        result[key] = true;
      }
      return result;
    }, {
      'type': true,
      'children': true
    });
  }

  getType(): string {
    return this._type;
  }

  getChildType(): string | undefined {
    return this._childType;
  }

  doHandler(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): HandleData | undefined {
    return this.handleDefaultProps(itemAttrs, bindKeys, parentData, configure);
  }

  doBefore(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void {
    handleChildProp(childProps, itemAttrs, ignoreAttrNames, configure);
    handleChildProps(childProps, itemAttrs, ignoreAttrNames, parentData, configure);
    this._propHandlerManger?.doBefore(childProps, itemAttrs, ignoreAttrNames, parentData, configure);

    if (this._beforeHandlerManger) {
      this._beforeHandlerManger.doBefore(childProps, itemAttrs, ignoreAttrNames, parentData, configure);
    }
  }

  doAfter(childProps: ChildProps, itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): void {
    if (this._afterHandlerManger) {
      this._afterHandlerManger.doAfter(childProps, itemAttrs, bindKeys, parentData, configure);
    }
  }

  handleDefaultProps(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): HandleData | undefined {
    if (itemAttrs && itemAttrs.type) {
      // 只有一个组件的属性需要处理

      const childWrapper = createChildWrapper(itemAttrs.type, parentData, this.getChildType());
      const childProps = childWrapper.childProps;
      const nextParentData = childWrapper.parentData;

      const ignoreAttrNamesByBefore: Record<string, boolean> = {};

      this.doBefore(childProps, itemAttrs, ignoreAttrNamesByBefore, nextParentData, configure);

      const ignoreAttrNames = this.ignoreAttrNames;
      for (const key of Object.keys(itemAttrs)) {
        const value = itemAttrs[key];
        if (!key || value === undefined) {
          continue;
        }
        if (ignoreAttrNames[key]) {
          continue;
        }
        if (ignoreAttrNamesByBefore[key]) {
          continue;
        }

        if (this._propHandlerManger) {
          if (this._propHandlerManger.doHandle(key, value, childProps, itemAttrs, parentData, configure)) {
            continue;
          }
        }

        childProps.props[key] = value;
      }

      setBindKeys(childProps, bindKeys);

      this.doAfter(childProps, itemAttrs, bindKeys, nextParentData, configure);

      return {
        topChildProps: childProps,
        topParentData: nextParentData,
        nextChildProps: childProps,
        nextParentData: nextParentData
      };
    }
  }

  setChildType(childType?: string) {
    this._childType = childType;
  }

}

/**
 * 相关类型处理器
 */
export class RelationTypeHandler extends BaseTypeHandler {
  protected _relationHandlerManger?: RelationHandlerManger;

  setRelationHandlerManger(relationHandlerManger?: RelationHandlerManger) {
    this._relationHandlerManger = relationHandlerManger;
  }

  doHandler(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): HandleData | undefined {
    if (itemAttrs) {
      if (this.isSampleTypeByChildType(itemAttrs, parentData)) {
        return super.doHandler(itemAttrs, bindKeys, parentData, configure);
      } else {
        if (this._relationHandlerManger) {
          const matchRelations = this._relationHandlerManger.getMatchRelations(itemAttrs, parentData, configure);
          if (matchRelations.length > 1) {
            // 有至少2个组件的属性需要处理
            const ignoreAttrNamesByBefore: Record<string, boolean> = {};
            let topChildProps: ChildProps | undefined;
            let topParentData: ParentData | undefined;
            let nextChildProps: ChildProps | undefined;
            let nextParentData: ParentData | undefined;
            // 处理属性
            let handleRelationDataList = this.getHandleDataByRelationHandlers(matchRelations, itemAttrs, ignoreAttrNamesByBefore, topParentData, configure);
            if (handleRelationDataList.length > 0) {
              const firstHandleRelationData = handleRelationDataList[0];
              if (firstHandleRelationData) {
                topChildProps = firstHandleRelationData.childProps;
                topParentData = firstHandleRelationData.parentData;
              }
              const lastHandleRelationData = handleRelationDataList[handleRelationDataList.length - 1];
              if (lastHandleRelationData) {
                nextChildProps = lastHandleRelationData.childProps;
                nextParentData = lastHandleRelationData.parentData;
              }

              // 处理数据
              const ignoreAttrNames = this.ignoreAttrNames;
              const ignoreAttrProps = this.getMatchPropsAll(matchRelations);
              for (const key of Object.keys(itemAttrs)) {
                const value = itemAttrs[key];
                if (!key || value === undefined) {
                  continue;
                }
                if (ignoreAttrNames[key]) {
                  continue;
                }
                if (ignoreAttrNamesByBefore[key]) {
                  continue;
                }
                if (ignoreAttrProps.includes(key)) {
                  continue;
                }

                let isMatched = false;
                for (let j = handleRelationDataList.length - 1; j >= 0; j--) {
                  const handleRelationData = handleRelationDataList[j];
                  if (handleRelationData) {
                    const {childProps, relationHandler} = handleRelationData;
                    if (relationHandler.doHandle(key, value, childProps, itemAttrs, parentData, configure)) {
                      isMatched = true;
                      break;
                    }
                  }
                }
                if (!isMatched) {
                  if (nextChildProps) {
                    nextChildProps.props[key] = value;
                  }
                }
              }

              for (let i = 0; i < handleRelationDataList.length; i++) {
                const handleRelationData = handleRelationDataList[i];
                if (handleRelationData) {
                  const {childProps, parentData, relationHandler} = handleRelationData;

                  setBindKeys(childProps, bindKeys);

                  if (relationHandler instanceof BaseRelationHandler) {
                    relationHandler.doAfter(childProps, itemAttrs, bindKeys, parentData, configure);
                  }

                }
              }

            }

            return {
              topChildProps: topChildProps,
              topParentData: topParentData,
              nextChildProps: nextChildProps,
              nextParentData: nextParentData
            };
          }
        }
        return super.doHandler(itemAttrs, bindKeys, parentData, configure);
      }
    }
  }

  isSampleTypeByChildType(itemAttrs: ItemAttrs, parentData: ParentData): boolean {
    if (parentData.childType) {
      if (itemAttrs.type) {
        if (typeof itemAttrs.type === 'string') {
          return itemAttrs.type === parentData.childType;
        }
      }
      if (itemAttrs.handler) {
        return itemAttrs.handler === parentData.childType;
      }
    } else {
      return true;
    }
    return false;
  }

  getHandleDataByRelationHandlers(relationHandlers: RelationHandler[], itemAttrs: ItemAttrs, ignoreAttrNamesByBefore: Record<string, boolean>, parentData: ParentData, configure: Configure): RelationWrapperData[] {
    const result: RelationWrapperData[] = [];
    if (relationHandlers.length > 0) {
      let childPropsTemp;
      let parentDataTemp = parentData;
      for (let i = 0; i < relationHandlers.length; i++) {
        const relationHandler = relationHandlers[i];
        if (relationHandler) {
          const relationWrapper = createRelationWrapper(relationHandler, itemAttrs, parentDataTemp);
          const childPropsItem = relationWrapper.childProps;
          const parentDataItem = relationWrapper.parentData;

          if (relationHandler.isHandleProp()) {
            handleChildProp(childPropsItem, itemAttrs, ignoreAttrNamesByBefore, configure);
            handleChildProps(childPropsItem, itemAttrs, ignoreAttrNamesByBefore, parentData, configure);
          }
          relationHandler.doBefore(childPropsItem, itemAttrs, ignoreAttrNamesByBefore, parentDataItem, configure);

          result.push(relationWrapper);

          if (childPropsTemp) {
            childPropsTemp.children = [childPropsItem];
          }

          childPropsTemp = childPropsItem;
          parentDataTemp = parentDataItem;
        }
      }
    }
    return result;
  }

  getMatchPropsAll(relationHandlers: RelationHandler[]) {
    const matchProps = [];
    if (relationHandlers.length > 0) {
      for (let i = 0; i < relationHandlers.length; i++) {
        const relationHandler = relationHandlers[i];
        matchProps.push(...relationHandler.getMatchProps());
      }
    }
    return matchProps;
  }
}

/**
 * 默认类型处理器
 */
export class DefaultTypeHandler extends BaseTypeHandler {

}

/**
 * 匹配任意的类型处理器
 */
export class AnyTypeHandler extends BaseTypeHandler {

  constructor() {
    super('*');
  }

}

/**
 * 默认处理器管理器
 */
export class DefaultHandlerManger implements HandlerManger {

  doHandle(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): HandleData | undefined {
    const handler = this.getHandler(itemAttrs, bindKeys, parentData, configure);
    return handler.doHandler(itemAttrs, bindKeys, parentData, configure);
  }

  getHandler(itemAttrs: ItemAttrs, bindKeys: BindKeyInfo[], parentData: ParentData, configure: Configure): TypeHandler {
    if (parentData.childType) {
      let handler = configure.getHandlerByType(parentData.childType);
      if (!handler) throw new Error('no * match child handler-name: ' + parentData.childType);
      return handler;
    }
    if (itemAttrs.type) {
      if (typeof itemAttrs.type === 'string') {
        let handler = configure.getHandlerByType(itemAttrs.type);
        if (!handler) handler = configure.getAnyHandler();
        if (!handler) throw new Error('no * match type handler-name: any');
        return handler;
      }
    }
    if (itemAttrs.handler) {
      let handler = configure.getHandlerByType(itemAttrs.handler);
      if (!handler) handler = configure.getAnyHandler();
      if (!handler) throw new Error('no * match handler handler-name: ');
      return handler;
    }
    throw new Error('no * match type handler-name: ' + itemAttrs.prop || itemAttrs.label);
  }

}

/**
 * 特殊属性处理器
 */
export class SpecialPropHandler implements PropHandler {
  protected readonly _iconName: string;

  constructor(iconName: string) {
    this._iconName = iconName;
  }

  doHandle(key: string, value: string, childProps: ChildProps, itemAttrs: ItemAttrs, parentData: ParentData, configure: Configure): boolean {
    // 处理特殊属性
    if (key === 'buttonText') {
      childProps.children.push({
        key: getUuid(),
        prop: '',
        name: 'default',
        text: value,
        props: {},
        children: []
      });
      return true;
    }
    if (key === 'buttonIcon') {
      const iconName = this._iconName;
      if (iconName) {
        childProps.children.push({
          key: getUuid(),
          prop: '',
          name: 'icon',
          type: iconName,
          props: {
            name: value
          },
          children: []
        });
        return true;
      }
    }
    if (key === 'prefixText') {
      childProps.children.push({
        key: getUuid(),
        prop: '',
        name: 'prefix',
        text: value,
        props: {},
        children: []
      });
      return true;
    }
    if (key === 'prefixIcon') {
      const iconName = this._iconName;
      if (iconName) {
        childProps.children.push({
          key: getUuid(),
          prop: '',
          name: 'prefix',
          type: iconName,
          props: {
            name: value
          },
          children: []
        });
        return true;
      }
    }
    if (key === 'suffixText') {
      childProps.children.push({
        key: getUuid(),
        prop: '',
        name: 'suffix',
        text: value,
        props: {},
        children: []
      });
      return true;
    }
    if (key === 'suffixIcon') {
      const iconName = this._iconName;
      if (iconName) {
        childProps.children.push({
          key: getUuid(),
          prop: '',
          name: 'suffix',
          type: iconName,
          props: {
            name: value
          },
          children: []
        });
        return true;
      }
    }
    return false;
  }

}

/**
 * 默认表单项规则前置处理器
 */
export class FormItemRulesBeforeHandler implements BeforeHandler {
  protected readonly _formItemName: string;
  protected readonly _propRuleName: string;
  protected readonly _attrRuleName: string;

  constructor(formItemName: string, propRuleName: string, attrRuleName: string) {
    this._formItemName = formItemName;
    this._propRuleName = propRuleName;
    this._attrRuleName = attrRuleName;
  }

  doBefore(childProps: ChildProps, itemAttrs: ItemAttrs, ignoreAttrNames: Record<string, boolean>, parentData: ParentData, configure: Configure): void {
    const formItemName = this._formItemName;
    const propRuleName = this._propRuleName;
    const attrRuleName = this._attrRuleName;
    if (formItemName && propRuleName && attrRuleName) {
      if (childProps.type === formItemName) {
        childProps.props.path = itemAttrs.prop;
        childProps.props[propRuleName] = this.getFormItemRules(childProps, itemAttrs, attrRuleName);
        ignoreAttrNames.minlength = true;
        ignoreAttrNames.maxlength = true;
        ignoreAttrNames.lengthMessage = true;
        ignoreAttrNames.regex = true;
        ignoreAttrNames.regexMessage = true;
        ignoreAttrNames.required = true;
        ignoreAttrNames.requiredMessage = true;
        ignoreAttrNames[propRuleName] = true;
      }
    }
  }

  getFormItemRules(childProps: ChildProps, itemAttrs: ItemAttrs, rulesName: string): Record<string, any>[] {
    const rules = [];
    if (itemAttrs[rulesName]) {
      rules.push(...itemAttrs[rulesName]);
    }
    const requiredRule = this.getRequiredRule(childProps, itemAttrs);
    if (requiredRule) {
      rules.push(requiredRule);
    }
    const lengthRule = this.getLengthRule(childProps, itemAttrs);
    if (lengthRule) {
      rules.push(lengthRule);
    }
    const regexRule = this.getRegexRule(childProps, itemAttrs);
    if (regexRule) {
      rules.push(regexRule);
    }
    if (rules.length > 0) {
      return rules;
    }
  }

  getRequiredRule(childProps: ChildProps, itemAttrs: ItemAttrs) {
    if (itemAttrs.required !== undefined && itemAttrs.required) {
      const placeholder = itemAttrs.requiredMessage || itemAttrs.placeholder;
      if (itemAttrs.datatype && itemAttrs.datatype === 'array') {
        return {
          required: true,
          trigger: [
            'input',
            'blur'
          ],
          validator: (rule: any, value: any[]) => {
            if (value && value.length > 0) {
              return true;
            }
            return new Error(placeholder);
            // return new Promise<void>((resolve, reject) => {
            //   if (value && value.length > 0) {
            //     resolve();
            //   } else {
            //     reject(new Error(placeholder));
            //   }
            // });
          }
        };
      } else {
        return {
          required: true,
          message: placeholder,
          trigger: [
            'input',
            'blur'
          ]
        };
      }
    }
  }

  getLengthRule(childProps: ChildProps, itemAttrs: ItemAttrs) {
    if (itemAttrs.minlength !== undefined && itemAttrs.minlength > 0 &&
      itemAttrs.maxlength !== undefined && itemAttrs.maxlength > 0) {
      let lengthMessage = itemAttrs.lengthMessage;
      if (lengthMessage) {
        // noinspection RegExpRedundantEscape
        lengthMessage = lengthMessage.replace(/\{min\}/g, itemAttrs.minlength + '')
          .replace(/\{max\}/g, itemAttrs.maxlength + '');
      }
      return {
        min: itemAttrs.minlength,
        max: itemAttrs.maxlength,
        message: lengthMessage,
        trigger: [
          'blur'
        ]
      };
    } else if (itemAttrs.minlength !== undefined && itemAttrs.minlength > 0) {
      let lengthMessage = itemAttrs.lengthMessage;
      if (lengthMessage) {
        // noinspection RegExpRedundantEscape
        lengthMessage = lengthMessage.replace(/\{min\}/g, itemAttrs.minlength + '');
      }
      return {
        min: itemAttrs.minlength,
        message: lengthMessage,
        trigger: [
          'blur'
        ]
      };
    } else if (itemAttrs.maxlength !== undefined && itemAttrs.maxlength > 0) {
      let lengthMessage = itemAttrs.lengthMessage;
      if (lengthMessage) {
        // noinspection RegExpRedundantEscape
        lengthMessage = lengthMessage.replace(/\{max\}/g, itemAttrs.maxlength + '');
      }
      return {
        max: itemAttrs.maxlength,
        message: lengthMessage,
        trigger: [
          'blur'
        ]
      };
    }
  }

  getRegexRule(childProps: ChildProps, itemAttrs: ItemAttrs) {
    if (itemAttrs.regex !== undefined && itemAttrs.regex > 0) {
      const regexp = new RegExp(itemAttrs.regex);
      const regexMessage = itemAttrs.regexMessage || 'mismatching rule';
      return {
        required: true,
        trigger: [
          'blur'
        ],
        validator: (rule: any, value: string) => {
          if (regexp.test(value)) {
            return true;
          }
          return new Error(regexMessage);
        }
      };
    }
  }

  getChildrenPlaceholder(childProps: ChildProps, prop?: string): string | undefined {
    if (prop && childProps) {
      const children = childProps.children;
      if (children && children.length > 0) {
        for (let i = 0; i < children.length; i++) {
          const child = children[i];
          if (!child) {
            continue;
          }
          if (child.prop === prop && child.type !== 'formItem') {
            return child.props.placeholder;
          } else {
            const placeholder = this.getChildrenPlaceholder(child, prop);
            if (placeholder) {
              return placeholder;
            }
          }
        }
      }
    }
  }

}
